#ifndef INSTANCE_H
#define INSTANCE_H
#include <vector>
#include <string>
#include <algorithm>
#include <iterator>
#include "attribute.h"
#include "lexcal.h"
#include "attribute_info.h"

//===============================================================
//  Name: instance
//    This is a class for a tuple in the data set.
//    Both  training set tuples and  test set are in this form.
//    Include instancs and class label.
//  Author:junix(NJU)
//  Date: 2007-11-15
//===============================================================

class instance
{
public:
//===============================================================
// Constructor and Deconstructor
//===============================================================
    instance ()
    {
        _missing = false;
    }

    //construct the object from a tuple (here is a formating string.)
    instance (string ins, vector < int > sel, vector < attribute_info > *infos)
    {
        vector < string > tuples = str_to_vector (ins, ',');
        _missing = false;

        //major is the last one in the tuple.
	_major.id(0);
        _major.numeric(atof(tuples.front().c_str()) );
        _major.discrete(tuples.front());
        _major.missing(false);
        _major.set_attr_infos (infos);

        for (int i = 0; i < sel.size (); i++)
        {
            attribute attr (sel.at (i), tuples.at (sel.at (i)), infos);

            if (attr.missing ())
                _missing = true;

            _attrs.push_back (attr);

        }
	
        //label is the last one in the tuple.
        _label.id (infos->size () - 1);
        _label.discrete (tuples.back());//label is discrete
        _label.set_attr_infos (infos);
    }

    //Copy Constructor of instance
    instance (const instance & ins)
    {
        _missing = ins._missing;
        copy (ins._attrs.begin (), ins._attrs.end (), back_inserter (_attrs));
        _label = ins._label;
        _major = ins._major;
    }

    bool same_with (const instance & ins)
    {
	    if(_missing ||ins._missing)
		    return false;

	    for(int i=0;i<_attrs.size();i++)
	    {
                if( ! _attrs.at(i).same_with(ins._attrs.at(i)) )
			return false;
	    }
	    return true;
    }
//This function is used to fix all the 
//missing value in all the test set tuples.
    int fix_missing (instance & ave)
    {
        if (!_missing)
            return 0;

        vector<attribute>::iterator iter = _attrs.begin();
        while (iter != _attrs.end())
        {
            if (iter->missing())
            {
                *iter = ave.attr(iter->id());
                iter->_missing = false;
            }
            iter++;
        }

        _missing = false;

        return 0;
    }

    //get the attribution whose id is the argument
    attribute& attr(int id)
    {
        vector<attribute>::iterator iter = _attrs.begin();
        while (iter != _attrs.end())
        {
            if (iter->id() == id)
                return  *iter;
            iter++;
        }
    }

    attribute_info& label_info()
    {
        return _label._attr_infos->back();
    }

//============================================================
// Print
//============================================================
    void print ()
    {
        copy(_attrs.begin(),_attrs.end(),ostream_iterator<attribute>(cout));
        cout<<_label;
        cout<<std::endl;
    }

    friend ostream& operator <<(ostream& os, const instance& ins)
    {
        os<<"major: "<<ins._major._numeric<<endl;
        copy(ins._attrs.begin(),ins._attrs.end(),ostream_iterator<attribute>(os));
        os<<ins._label;
        os<<std::endl;
        os<<std::endl;
        return os;
    }

    bool missing ()
    {
        return _missing;
    }

    //major value
    float major()
    {
        return _major.numeric();
    }
 
//============================================================
//  Member
//============================================================
    bool _missing;
    vector <attribute> _attrs;
    attribute _label;
    attribute _major;
};
#endif
